package com.hmall.trade.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.api.client.CartClient;
import com.hmall.api.client.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.common.exception.BadRequestException;
import com.hmall.common.utils.UserContext;
import com.hmall.trade.constants.MqConstants;
import com.hmall.trade.domain.dto.OrderFormDTO;
import com.hmall.trade.domain.po.Order;
import com.hmall.trade.domain.po.OrderDetail;
import com.hmall.trade.mapper.OrderMapper;
import com.hmall.trade.service.IOrderDetailService;
import com.hmall.trade.service.IOrderService;
import lombok.RequiredArgsConstructor;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 订单服务实现类
 * 实现订单相关业务逻辑，包括订单创建、支付处理和订单取消
 */
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    // 商品服务远程调用客户端
    private final ItemClient itemClient;

    // 订单详情服务
    private final IOrderDetailService detailService;

    // 购物车服务远程调用客户端
    private final CartClient cartClient;

    // RabbitMQ消息发送模板
    private final RabbitTemplate rabbitTemplate;

    /**
     * 创建订单核心方法
     * 使用Seata全局事务保证跨服务操作的一致性
     */
    @Override
    @GlobalTransactional // 使用Seata分布式事务
    public Long createOrder(OrderFormDTO orderFormDTO) {

        // 1. 构建并保存订单主信息
        Order order = buildOrder(orderFormDTO);

        // 2. 保存订单详情
        List<OrderDetail> details = buildDetails(order.getId(), orderFormDTO);
        detailService.saveBatch(details);

        // 3. 扣减库存
        deductStock(orderFormDTO.getDetails());

        // 4. 清理购物车
        clearCartItems(orderFormDTO.getDetails());

        // 5. 发送延迟消息，用于超时未支付自动关闭订单
        sendOrderDelayMessage(order.getId());

        return order.getId();
    }

    /**
     * 构建订单主信息
     */
    private Order buildOrder(OrderFormDTO orderFormDTO) {

        // 1.1 查询商品信息
        List<OrderDetailDTO> detailDTOS = orderFormDTO.getDetails();
        Map<Long, Integer> itemNumMap = detailDTOS.stream()
                .collect(Collectors.toMap(OrderDetailDTO::getItemId, OrderDetailDTO::getNum));
        Set<Long> itemIds = itemNumMap.keySet();

        // 1.2 远程调用商品服务查询商品
        List<ItemDTO> items = itemClient.queryItemByIds(itemIds);
        if (items == null || items.size() < itemIds.size()) {
            throw new BadRequestException("商品不存在");
        }

        // 1.3 计算订单总金额
        int total = items.stream()
                .mapToInt(item -> item.getPrice() * itemNumMap.get(item.getId()))
                .sum();

        // 1.4 构建订单对象
        Order order = new Order();
        order.setTotalFee(total);
        order.setPaymentType(orderFormDTO.getPaymentType());
        order.setUserId(UserContext.getUser()); // 从上下文中获取当前用户ID
        order.setStatus(1); // 初始状态：未支付
        order.setCreateTime(LocalDateTime.now());

        // 1.5 保存订单到数据库
        save(order);
        return order;
    }

    /**
     * 构建订单详情列表
     */
    private List<OrderDetail> buildDetails(Long orderId, OrderFormDTO orderFormDTO) {
        List<OrderDetailDTO> detailDTOS = orderFormDTO.getDetails();
        Map<Long, Integer> itemNumMap = detailDTOS.stream()
                .collect(Collectors.toMap(OrderDetailDTO::getItemId, OrderDetailDTO::getNum));

        // 查询商品信息
        List<ItemDTO> items = itemClient.queryItemByIds(itemNumMap.keySet());

        // 构建订单详情列表
        return items.stream()
                .map(item -> {
                    OrderDetail detail = new OrderDetail();
                    detail.setOrderId(orderId);
                    detail.setItemId(item.getId());
                    detail.setName(item.getName());
                    detail.setSpec(item.getSpec());
                    detail.setPrice(item.getPrice());
                    detail.setNum(itemNumMap.get(item.getId()));
                    detail.setImage(item.getImage());
                    return detail;
                })
                .collect(Collectors.toList());
    }

    /**
     * 扣减库存
     */
    private void deductStock(List<OrderDetailDTO> details) {
        try {
            itemClient.deductStock(details);
        } catch (Exception e) {
            // 库存不足时回滚事务
            throw new RuntimeException("库存不足！", e);
        }
    }

    /**
     * 清理购物车
     */
    private void clearCartItems(List<OrderDetailDTO> details) {
        Set<Long> itemIds = details.stream()
                .map(OrderDetailDTO::getItemId)
                .collect(Collectors.toSet());
        cartClient.deleteCartItemByIds(itemIds);
    }

    /**
     * 发送订单延迟消息
     */
    private void sendOrderDelayMessage(Long orderId) {
        rabbitTemplate.convertAndSend(
                MqConstants.DELAY_EXCHANGE_NAME,
                MqConstants.DELAY_ORDER_KEY,
                orderId,
                message -> {
                    message.getMessageProperties().setDelay(10 * 60 * 1000); // 10分钟延迟
                    return message;
                }
        );
    }

    /**
     * 标记订单支付成功
     */
    @Override
    @Transactional
    public void markOrderPaySuccess(Long orderId) {

        Order order = new Order();
        order.setId(orderId);
        order.setStatus(2); // 已支付
        order.setPayTime(LocalDateTime.now());
        updateById(order);

    }

    /**
     * 取消订单并恢复库存
     */
    @Override
    @Transactional
    public void cancelOrder(Long orderId) {

        // 1. 更新订单状态为已取消
        Order order = new Order();
        order.setId(orderId);
        order.setStatus(5); // 已取消
        order.setCloseTime(LocalDateTime.now());
        updateById(order);

        // 2. 恢复库存
        List<OrderDetail> orderDetails = detailService.lambdaQuery()
                .eq(OrderDetail::getOrderId, orderId)
                .list();

        List<OrderDetailDTO> detailDTOS = orderDetails.stream()
                .map(detail -> {
                    OrderDetailDTO dto = new OrderDetailDTO();
                    dto.setItemId(detail.getItemId());
                    dto.setNum(-detail.getNum()); // 负数表示恢复库存
                    return dto;
                })
                .collect(Collectors.toList());

        itemClient.deductStock(detailDTOS);
    }
}